import pandas as pd
import numpy as np

pd.set_option('display.unicode.east_asian_width', True)
data = pd.DataFrame([['张三', '男', 90, 85],
                     ['李四', '女', 58, 91],
                     ['王五', '男', 84, 52]],
                    columns=['姓名', '性别', '语文', '数学'])

"""Series数据处理
1.map：传入字典或函数，把series中的元素逐个当作参数传入到字典或函数中，得到映射后的值
2.apply：传入函数，作用原理和map方法相同，区别在于apply传入函数的同时可以传入函数的参数
>>> s_map
0      male
1    female
2      male
>>> s_mapna
0    male
1     NaN
2    male
>>> s_func
0      male
1    female
2      male
>>> s_apply
0    140
1    108
2    134
"""
# map使用字典，在字典中找不到的值将转换为NaN，除非字典具有默认值（例如defaultdict）
s_map = data['性别'].map({'男': 'male', '女': 'female'})
s_mapna = data['性别'].map({'男': 'male'})
# map使用函数，为了避免将函数作用于原本的空值（并将它们保留为NaN），可以使用na_action='ignore'
s_mapfunc = data['性别'].map(lambda x: 'male' if x == '男' else 'female', na_action='ignore')
# apply
s_apply = data['语文'].apply(lambda x, a: x + a, args=(50,))
s_apply2 = data['语文'].apply(lambda x, *args: x + sum(args), args=(50, 10))  # 不定长参数
s_apply3 = data['语文'].apply(lambda x, **kwargs: x + sum(kwargs.values()), a=50, b=10)  # 不定长命名参数

"""DataFrame数据处理
1.apply
    -axis=0：对每列columns执行指定函数。axis=1：对每行row执行指定函数。
    -无论axis=0还是axis=1，其传入指定函数的默认形式均为Series，可以通过设置raw=True传入numpy数组
    -执行过程为将每个Series传入函数中执行，再将每个执行结果整合在一起作为apply的返回值（所以函数返回
     单个元素时apply返回Series，函数返回Series时apply返回DataFrame）。
    -DataFrame的apply和Series的apply一样，传入函数的同时可以传入函数的参数
>>> df_apply1
语文    232
数学    228
>>> df_apply3
       语文      数学
0  4.499810  4.442651
1  4.060443  4.510860
2  4.430817  3.951244
>>> df_apply4
0     3.535534
1    23.334524
2    22.627417

2.applymap - 对DataFrame中的每个单元格执行指定函数的操作
>>> df_applymap
     语文    数学
0    优秀    及格
1  不及格    优秀
2    及格  不及格
"""
# apply按列
df_apply1 = data[['语文', '数学']].apply(lambda s: s.sum())  # 对每列进行求和。s.sum()返回单个值，所以apply返回Series）
df_apply2 = data[['语文', '数学']].apply(np.sum)  # 和上面效果相同
df_apply3 = data[['语文', '数学']].apply(np.log)  # 求每列元素的对数，返回DataFrame
# apply按行
def apply_std(s: pd.Series):
    series = s[['语文', '数学']]
    return series.std()
df_apply4 = data.apply(apply_std, axis=1)  # 求每行中语文和数学的标准差，返回Series

# applymap
def applymap_level(x):
    if x >= 90:
        return '优秀'
    elif x >= 60:
        return '及格'
    else:
        return '不及格'
df_applymap = data[['语文', '数学']].applymap(applymap_level)

